/* $Id: util.c 57 2007-03-25 09:14:34Z aldleonm $
 */
#include "util.h"
#include "extern.h"
#include "encdb.h"

void *
alloc(size_t size)
{
	void *temp = malloc(size);

	if (temp == NULL) {
		fprintf(stderr,
						"alloc(): %s , error allocating memory.\n", strerror(errno));
		return NULL;
	}

	memset(temp,0,size);
	return temp;
}


/* @file util.c
 * @brief return error and optionaly a errno var
 * 	if err_flag is > 0 errno is printed.
 * 	this function should be used in conbination with atexit();
 */
int
perrx(int ret, char *errmsg, int err_flag)
{
	if (err_flag) {
		fprintf(stderr, "%s : %s\n", errmsg, strerror(errno));
	} else {
		fprintf(stderr, "%s\n", errmsg);
	}
	exit(ret);
}


/* @brief the cleanup function
 * 	atexit() was doing weid stuff, better luck next time
 * 	@param void *freeptr 	if given, it will free the allocated memory
 */
void
before_exit(void *freeptr)
{
	if (db_i->action == WRITE || db_i->action == DELETE
			|| db_i->action == CREATE) {
		if (setID() != 0) {
			fprintf(stderr, "before_exit(): error calling setID().\n");
		}
	}

	if ( freeptr == NULL ) {
		free(freeptr);
	}

	CloseDB(db_i->pdb);
}


/* @brief 
 * @param 
 * @note
 */
char *
ed_getpass(char *pass)
{
	char *passref = NULL;	/* password reference (where to look for the password) */
	char *file = NULL; /* -p file:  */
	int f = 0;
	struct stat st;
	size_t r = 0;
	size_t buffsz = 1024;

	if ( pass == NULL ) {
		goto askfromterm;

	} else if (strncmp("file:", pass, 5) == 0) {
		passref = AA_tokenizer(pass, ":", 0, 0);
		file = AA_tokenizer(pass, ":", 1, 0);

		f = open(file, O_RDONLY);
		if (f == -1)
			return NULL;
		if (fstat(f, &st) != 0) {
			fprintf(stderr, "%s\n", strerror(errno));
			return NULL;
		}	

		if (S_ISREG(st.st_mode)) {
			void *fbuf = alloc(st.st_size);
			if ((read(f, fbuf, st.st_size)) < st.st_size) {
				fprintf(stderr, "Error reading from file %s.\n", passref);
				return NULL;
			}
			/* XXX C-book:197,98 read */
			char *t = fbuf;
			t[st.st_size-1] = NULL;	
			return fbuf;
		} else if (S_ISFIFO(st.st_mode)) {
			void *fbuf = alloc(buffsz);
			if ((read(f, fbuf, buffsz)) < 1 ) {
				fprintf(stderr, "Error reading from file %s.\n", passref);
			}
			void *t = memchr(fbuf,'\n',buffsz);
			strncpy(t,"\0",1);
			return fbuf;
		}

		if (close(f))
			return NULL;

	} else {
		goto askfromterm;
	}

askfromterm:
	{
	
		int c=0;
		int maxsz=512;
		void *tmps = alloc (maxsz);
		void *tmps2 = alloc (maxsz);
			
    	struct termios currsettings, noechosettings;
	
		memset(&currsettings,0,sizeof(currsettings));
		memset(&noechosettings,0,sizeof(noechosettings));
	
   		tcgetattr(0, &currsettings);         
   		noechosettings = currsettings;                   
    	noechosettings.c_lflag = ~(ICANON | ECHO); 
	
		/* tcsetattr(0, TCSANOW, &noechosettings); apply settings */
		tcsetattr(0, TCSADRAIN, &noechosettings); /* apply settings */
		fprintf(stdout,"Enter password, will not echo.\nPassword:");
		if ( fscanf(stdin,"%s",tmps) ) {
			fprintf(stdout,"\nVerify password.\nPassword:");
			if ( fscanf(stdin,"%s",tmps2) ) { 
				if ( (strncmp(tmps,tmps2,maxsz)) != 0 ) {
					fprintf(stdout,"\nPasswords do not match!\n");
					tcsetattr(0, TCSANOW, &currsettings);
					return NULL;
				}
			}
			fprintf(stdout,"\n");
			tcsetattr(0, TCSANOW, &currsettings);
			return (char *)tmps;
		} else {
			fprintf(stdout,"\n");
			tcsetattr(0, TCSANOW, &currsettings);
			fprintf(stderr, "Error reading from terminal.\n");
			return NULL;
		}
	}

}


#define MY_TOKENIZER_DMAPSZ 2000

/** return word at position 'int afterp' in contrast
 * 			 with delimiter 'const char *deli' and the option of returning 'all' words
 * 			 from position.
 *
 * @usage
 * 			It behaves like strtok(), with the exeptions of not modifying the given
 * 			string and having the option of printing the remaining string after
 * 			the token specified. Also has the feature of the delimiter being more
 * 			than one character. and lame.
 *
 * @param s				String to chop.
 * @param deli		Delimiter string or char.
 * @param afterp	If less than 1, print one token, else, print all after tokens.
 * @param all     Switch to activate the capability of printing the remainder
 *                 string if higher than zero.
 *
 * @notes this function does not change s ; this function does not chk for err;
 * 	the string must be null terminated.
 *
 */

char *
AA_tokenizer(char *s, const char *deli, int afterp, int all)
{

	static void *dmap[MY_TOKENIZER_DMAPSZ];	/* map of delimiters; position in string */
	static int dmap_i;	/* delimiters count */
	static char *lstr;	/* last copy of 's' */
	static int iafterp;	/* internal afterp */
	static char *cpdeli;	/* copy of delimiter string */
	void *t_cps = NULL;	/* temp copy of copy of 's'/'lstr' */
	char *cps, *nsp, *sp = NULL;	/* cps: copy of string char *s; parameter 0 */
	char *w, *wa = NULL;	/* word */
	char chr;	/* character */
	size_t deli_len, stlen_tmp;
	int i, c;

	c = i = 0;

	if (s == NULL) {
		cps = strdup(lstr);
		stlen_tmp = strlen(lstr);
	} else {
		cps = strdup(s);	/* work with a copy of the string */
		lstr = strdup(s);	/* another copy incase for later use */
		stlen_tmp = strlen(s);
		cpdeli = strdup(deli);	/* copy of the delimiter */
		dmap_i = 0;
	}


	deli_len = strlen(deli);

/* build delimiter map */
	if (dmap_i == 0 || (strcmp(deli, cpdeli)) != 0) {
		dmap[dmap_i++] = (void *) cps;	/* afterp starts from zero '0' */

		while (((chr = *(cps + c)) != '\0') && (dmap_i <= MY_TOKENIZER_DMAPSZ)) {
			i = 0;
			if (chr == (*deli)) {	/* find the first char of delimiter */
				t_cps = (void *) cps + c;
				while ((i <= deli_len) && *(deli + i) == *(cps + c + i)) {
					i++;
				}
				if (i == deli_len) {
					dmap[dmap_i++] = t_cps + i;
					c = c + i;
				}
			}	/* END-IF:2 */
			c++;
		}	/* END-WHILE */

	}

	/*
	   END-IF:1 
	 */
	/*
	   one token 
	 */
	if (all < 1) {
		/*
		 * sp   :  is the starting position
		 * nsp  :  is next position
		 */
		sp = dmap[afterp];

		/*
		   if on last delimiter match, dont get the next delimiter position,
		   * just use the last pointer-addr of string.
		 */
		if ((afterp != 0) && (afterp == (dmap_i - 1))) {
			nsp = &cps[stlen_tmp];
			nsp = nsp + 1;
		} else {
			nsp = dmap[afterp + 1];
		}

		nsp = nsp - deli_len;

		void *temp = malloc(nsp - sp + 1);

		if (temp == NULL) {
			fprintf(stderr, "Error allocating memory: malloc().\n");
			return NULL;
		}

		w = (char *) memset(temp, 0, nsp - sp);

		wa = w;

		while (((void *) sp) != (void *) nsp) {
			*w++ = *sp++;
		}
		return wa;
	}
	/* all tokens after 'afterp' */
	else {
		sp = dmap[afterp];
		return sp;
	}

}

/* file end */

/*
 vim: ts=4 
*/
